use anchor_lang::prelude::*;
use anchor_spl::associated_token::AssociatedToken;
use anchor_spl::token::{self, Burn, Mint, MintTo, Token, TokenAccount};

declare_id!("DW6xwBgnBY6MUf7J4i8FwaqmncfvbKvW9hN9HmCyhDLH");

#[program]
pub mod ignite_contracts {
    use super::*;

    /// 初始化工厂合约
    pub fn initialize_factory(ctx: Context<InitializeFactory>) -> Result<()> {
        let factory = &mut ctx.accounts.factory;
        factory.authority = ctx.accounts.authority.key();
        factory.total_tokens = 0;
        factory.graduation_threshold = 3 * 1_000_000_000; // 69 SOL in lamports
        factory.curve_slope = 1_000_000; // 斜率常数
        factory.is_paused = false;
        factory.total_graduated = 0;
        factory.total_volume = 0;

        msg!("Factory initialized with authority: {}", factory.authority);
        Ok(())
    }

    /// 创建新代币和联合曲线
    pub fn create_token(
        ctx: Context<CreateToken>,
        name: String,
        symbol: String,
        _uri: String,
        total_supply: u64,
    ) -> Result<()> {
        require!(name.len() <= 32, ErrorCode::NameTooLong);
        require!(symbol.len() <= 10, ErrorCode::SymbolTooLong);
        require!(total_supply > 0, ErrorCode::InvalidSupply);

        let factory = &mut ctx.accounts.factory;
        let curve = &mut ctx.accounts.bonding_curve;

        // 初始化联合曲线
        curve.mint = ctx.accounts.mint.key();
        curve.creator = ctx.accounts.creator.key();
        curve.total_supply = total_supply;
        curve.circulating_supply = 0;
        curve.sol_reserves = 0;
        curve.is_graduated = false;
        curve.created_at = Clock::get()?.unix_timestamp;
        curve.graduated_at = None;
        curve.liquidity_pool = None;
        curve.total_buys = 0;
        curve.total_sells = 0;

        // 更新工厂统计
        factory.total_tokens += 1;

        msg!("Token created: {} ({})", name, symbol);
        msg!("Bonding curve: {}", curve.key());

        Ok(())
    }

    /// 购买代币
    pub fn buy(ctx: Context<Buy>, sol_amount: u64) -> Result<()> {
        require!(sol_amount > 0, ErrorCode::InvalidAmount);
        require!(!ctx.accounts.factory.is_paused, ErrorCode::OperationsPaused);

        let curve = &mut ctx.accounts.bonding_curve;
        require!(!curve.is_graduated, ErrorCode::TokenGraduated);

        // 计算能购买的代币数量
        let token_amount = calculate_buy_amount(
            curve.circulating_supply,
            sol_amount,
            ctx.accounts.factory.curve_slope,
        )?;

        require!(
            curve.circulating_supply + token_amount <= curve.total_supply,
            ErrorCode::ExceedsSupply
        );

        // 转移 SOL 到曲线账户
        let transfer_instruction = anchor_lang::system_program::Transfer {
            from: ctx.accounts.buyer.to_account_info(),
            to: curve.to_account_info(),
        };
        anchor_lang::system_program::transfer(
            CpiContext::new(
                ctx.accounts.system_program.to_account_info(),
                transfer_instruction,
            ),
            sol_amount,
        )?;

        // 获取用于签名的种子
        let mint_key = ctx.accounts.mint.key();
        let bump = ctx.bumps.bonding_curve;
        let signer_seeds: &[&[&[u8]]] = &[&[b"curve", mint_key.as_ref(), &[bump]]];

        // 铸造代币给买家
        let mint_instruction = MintTo {
            mint: ctx.accounts.mint.to_account_info(),
            to: ctx.accounts.buyer_token_account.to_account_info(),
            authority: curve.to_account_info(),
        };
        token::mint_to(
            CpiContext::new_with_signer(
                ctx.accounts.token_program.to_account_info(),
                mint_instruction,
                signer_seeds,
            ),
            token_amount,
        )?;

        // 更新曲线状态
        curve.circulating_supply += token_amount;
        curve.sol_reserves += sol_amount;
        curve.total_buys += 1;

        // 更新工厂统计
        let factory = &mut ctx.accounts.factory;
        factory.total_volume += sol_amount;

        // 计算当前价格（用于事件）
        let current_price = if curve.circulating_supply > 0 {
            curve.sol_reserves * 1_000_000_000 / curve.circulating_supply
        } else {
            0
        };

        // 发出交易事件
        emit!(TokenTradeEvent {
            mint: curve.mint,
            trader: ctx.accounts.buyer.key(),
            is_buy: true,
            token_amount,
            sol_amount,
            new_price: current_price,
            market_cap: curve.sol_reserves,
            timestamp: Clock::get()?.unix_timestamp,
        });

        // 检查是否达到毕业阈值
        if curve.sol_reserves >= ctx.accounts.factory.graduation_threshold {
            // 触发毕业流程
            curve.is_graduated = true;
            
            // 发出毕业事件，通知外部系统
            emit!(TokenGraduatedEvent {
                mint: curve.mint,
                creator: curve.creator,
                final_market_cap: curve.sol_reserves,
                total_supply: curve.total_supply,
                timestamp: Clock::get()?.unix_timestamp,
            });
            
            msg!("Token graduated! Moving to DEX...");
            msg!("Final market cap: {} SOL", curve.sol_reserves);
            msg!("Ready for DEX liquidity pool creation");
        }

        msg!("Bought {} tokens for {} SOL", token_amount, sol_amount);

        Ok(())
    }

    /// 卖出代币
    pub fn sell(ctx: Context<Sell>, token_amount: u64) -> Result<()> {
        require!(token_amount > 0, ErrorCode::InvalidAmount);
        require!(!ctx.accounts.factory.is_paused, ErrorCode::OperationsPaused);

        let curve = &mut ctx.accounts.bonding_curve;
        require!(!curve.is_graduated, ErrorCode::TokenGraduated);
        require!(
            token_amount <= curve.circulating_supply,
            ErrorCode::InsufficientSupply
        );

        // 计算能获得的 SOL 数量
        let sol_amount = calculate_sell_amount(
            curve.circulating_supply,
            token_amount,
            ctx.accounts.factory.curve_slope,
        )?;

        require!(
            sol_amount <= curve.sol_reserves,
            ErrorCode::InsufficientReserves
        );

        // 销毁代币
        let burn_instruction = Burn {
            mint: ctx.accounts.mint.to_account_info(),
            from: ctx.accounts.seller_token_account.to_account_info(),
            authority: ctx.accounts.seller.to_account_info(),
        };
        token::burn(
            CpiContext::new(
                ctx.accounts.token_program.to_account_info(),
                burn_instruction,
            ),
            token_amount,
        )?;

        // 更新曲线状态（在转账前）
        curve.circulating_supply -= token_amount;
        curve.sol_reserves -= sol_amount;
        curve.total_sells += 1;

        // 转移 SOL 给卖家
        **ctx
            .accounts
            .seller
            .to_account_info()
            .try_borrow_mut_lamports()? += sol_amount;
        **curve.to_account_info().try_borrow_mut_lamports()? -= sol_amount;

        // 计算当前价格（用于事件）
        let current_price = if curve.circulating_supply > 0 {
            curve.sol_reserves * 1_000_000_000 / curve.circulating_supply
        } else {
            0
        };

        // 发出交易事件
        emit!(TokenTradeEvent {
            mint: curve.mint,
            trader: ctx.accounts.seller.key(),
            is_buy: false,
            token_amount,
            sol_amount,
            new_price: current_price,
            market_cap: curve.sol_reserves,
            timestamp: Clock::get()?.unix_timestamp,
        });

        msg!("Sold {} tokens for {} SOL", token_amount, sol_amount);

        Ok(())
    }

    /// 毕业到 DEX（仅限授权账户）
    pub fn graduate_to_dex(ctx: Context<GraduateToDex>) -> Result<()> {
        let curve = &mut ctx.accounts.bonding_curve;
        require!(!curve.is_graduated, ErrorCode::TokenAlreadyGraduated);
        require!(
            curve.sol_reserves >= ctx.accounts.factory.graduation_threshold,
            ErrorCode::ThresholdNotMet
        );

        // 计算用于 DEX 的资产分配
        let sol_for_liquidity = curve.sol_reserves * 80 / 100; // 80% 用于流动性
        let sol_for_creator = curve.sol_reserves * 20 / 100;   // 20% 给创建者
        
        // 计算剩余代币供应量（用于 DEX 流动性）
        let remaining_tokens = curve.total_supply - curve.circulating_supply;
        
        // 更新状态为已毕业
        curve.is_graduated = true;
        curve.graduated_at = Some(Clock::get()?.unix_timestamp);
        
        // 更新工厂统计
        let factory = &mut ctx.accounts.factory;
        factory.total_graduated += 1;
        
        // 转移创建者费用
        **ctx.accounts.creator.to_account_info().try_borrow_mut_lamports()? += sol_for_creator;
        **curve.to_account_info().try_borrow_mut_lamports()? -= sol_for_creator;
        
        // 发出毕业完成事件
        emit!(TokenGraduationCompletedEvent {
            mint: curve.mint,
            creator: curve.creator,
            sol_for_liquidity,
            sol_for_creator,
            remaining_tokens,
            dex_pool: None, // 将在实际创建池子后更新
            timestamp: Clock::get()?.unix_timestamp,
        });

        msg!("Token {} graduated to DEX", curve.mint);
        msg!("SOL for liquidity: {}", sol_for_liquidity);
        msg!("SOL for creator: {}", sol_for_creator);
        msg!("Tokens for liquidity: {}", remaining_tokens);

        Ok(())
    }

    /// 创建 Raydium 流动性池（扩展功能）
    pub fn create_liquidity_pool(ctx: Context<CreateLiquidityPool>) -> Result<()> {
        let curve = &ctx.accounts.bonding_curve;
        require!(curve.is_graduated, ErrorCode::TokenNotGraduated);
        require!(curve.liquidity_pool.is_none(), ErrorCode::PoolAlreadyCreated);

        // 这里需要与 Raydium SDK 集成
        // 目前作为占位符，实际实现需要：
        // 1. 调用 Raydium 的创建池子指令
        // 2. 存入 SOL 和代币作为初始流动性
        // 3. 获取 LP Token
        // 4. 销毁或锁定 LP Token

        msg!("Creating Raydium liquidity pool...");
        msg!("This function requires Raydium SDK integration");

        Ok(())
    }

    /// 紧急暂停（仅限工厂权限）
    pub fn emergency_pause(ctx: Context<EmergencyPause>) -> Result<()> {
        let factory = &mut ctx.accounts.factory;
        factory.is_paused = true;
        
        emit!(EmergencyPauseEvent {
            authority: ctx.accounts.authority.key(),
            timestamp: Clock::get()?.unix_timestamp,
        });

        msg!("Factory paused by authority");
        Ok(())
    }

    /// 恢复运行（仅限工厂权限）
    pub fn resume_operations(ctx: Context<ResumeOperations>) -> Result<()> {
        let factory = &mut ctx.accounts.factory;
        factory.is_paused = false;
        
        emit!(ResumeOperationsEvent {
            authority: ctx.accounts.authority.key(),
            timestamp: Clock::get()?.unix_timestamp,
        });

        msg!("Factory operations resumed");
        Ok(())
    }
}

// 辅助函数
fn calculate_buy_amount(current_supply: u64, sol_amount: u64, slope: u64) -> Result<u64> {
    // 简化的线性联合曲线计算
    // price = slope * supply / 1e9
    // sol_amount = slope * (end^2 - start^2) / (2 * 1e9)

    let start = current_supply as u128;
    let slope_u128 = slope as u128;
    let sol_u128 = sol_amount as u128;

    // 解二次方程求 token_amount
    let discriminant = start * start + 2 * sol_u128 * 1_000_000_000 / slope_u128;
    let end = (discriminant as f64).sqrt() as u128;
    let token_amount = end.saturating_sub(start);

    Ok(token_amount as u64)
}

fn calculate_sell_amount(current_supply: u64, token_amount: u64, slope: u64) -> Result<u64> {
    // 计算卖出代币能获得的 SOL
    let start = (current_supply - token_amount) as u128;
    let end = current_supply as u128;
    let slope_u128 = slope as u128;

    let sol_amount = slope_u128 * (end * end - start * start) / (2 * 1_000_000_000);

    Ok(sol_amount as u64)
}

// 账户结构
#[derive(Accounts)]
pub struct InitializeFactory<'info> {
    #[account(
        init,
        payer = authority,
        space = 8 + 32 + 8 + 8 + 8 + 1 + 8 + 8, // discriminator + pubkey + 6*u64 + bool
        seeds = [b"factory"],
        bump
    )]
    pub factory: Account<'info, Factory>,

    #[account(mut)]
    pub authority: Signer<'info>,

    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct CreateToken<'info> {
    #[account(mut)]
    pub factory: Account<'info, Factory>,

    #[account(
        init,
        payer = creator,
        space = 8 + 32 + 32 + 4 + 256 + 4 + 512 + 4 + 512 + 8 + 8 + 8 + 8 + 1 + 8 + 32 + 8 + 8 + 8 + 8, // Updated space for new fields
        seeds = [b"curve", mint.key().as_ref()],
        bump
    )]
    pub bonding_curve: Account<'info, BondingCurve>,

    #[account(
        init,
        payer = creator,
        mint::decimals = 9,
        mint::authority = bonding_curve,
    )]
    pub mint: Account<'info, Mint>,

    #[account(mut)]
    pub creator: Signer<'info>,

    pub token_program: Program<'info, Token>,
    pub system_program: Program<'info, System>,
    pub rent: Sysvar<'info, Rent>,
}

#[derive(Accounts)]
pub struct Buy<'info> {
    pub factory: Account<'info, Factory>,

    #[account(
        mut,
        seeds = [b"curve", mint.key().as_ref()],
        bump
    )]
    pub bonding_curve: Account<'info, BondingCurve>,

    #[account(mut)]
    pub mint: Account<'info, Mint>,

    #[account(
        init_if_needed,
        payer = buyer,
        associated_token::mint = mint,
        associated_token::authority = buyer,
    )]
    pub buyer_token_account: Account<'info, TokenAccount>,

    #[account(mut)]
    pub buyer: Signer<'info>,

    pub token_program: Program<'info, Token>,
    pub associated_token_program: Program<'info, AssociatedToken>,
    pub system_program: Program<'info, System>,
    pub rent: Sysvar<'info, Rent>,
}

#[derive(Accounts)]
pub struct Sell<'info> {
    pub factory: Account<'info, Factory>,

    #[account(
        mut,
        seeds = [b"curve", mint.key().as_ref()],
        bump
    )]
    pub bonding_curve: Account<'info, BondingCurve>,

    #[account(mut)]
    pub mint: Account<'info, Mint>,

    #[account(mut)]
    pub seller_token_account: Account<'info, TokenAccount>,

    #[account(mut)]
    pub seller: Signer<'info>,

    pub token_program: Program<'info, Token>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct GraduateToDex<'info> {
    pub factory: Account<'info, Factory>,

    #[account(
        mut,
        seeds = [b"curve", mint.key().as_ref()],
        bump
    )]
    pub bonding_curve: Account<'info, BondingCurve>,

    pub mint: Account<'info, Mint>,

    /// CHECK: Creator account to receive graduation fees
    #[account(mut)]
    pub creator: UncheckedAccount<'info>,

    #[account(
        constraint = authority.key() == factory.authority @ ErrorCode::Unauthorized
    )]
    pub authority: Signer<'info>,

    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct CreateLiquidityPool<'info> {
    #[account(
        mut,
        seeds = [b"curve", mint.key().as_ref()],
        bump
    )]
    pub bonding_curve: Account<'info, BondingCurve>,

    pub mint: Account<'info, Mint>,

    /// CHECK: Raydium program ID
    pub raydium_program: UncheckedAccount<'info>,

    /// CHECK: Pool state account
    #[account(mut)]
    pub pool_state: UncheckedAccount<'info>,

    /// CHECK: Pool LP mint
    #[account(mut)]
    pub pool_lp_mint: UncheckedAccount<'info>,

    pub authority: Signer<'info>,
    pub system_program: Program<'info, System>,
    pub token_program: Program<'info, Token>,
    pub rent: Sysvar<'info, Rent>,
}

#[derive(Accounts)]
pub struct EmergencyPause<'info> {
    #[account(
        mut,
        constraint = authority.key() == factory.authority @ ErrorCode::Unauthorized
    )]
    pub factory: Account<'info, Factory>,

    pub authority: Signer<'info>,
}

#[derive(Accounts)]
pub struct ResumeOperations<'info> {
    #[account(
        mut,
        constraint = authority.key() == factory.authority @ ErrorCode::Unauthorized
    )]
    pub factory: Account<'info, Factory>,

    pub authority: Signer<'info>,
}

// 数据结构
#[account]
pub struct Factory {
    pub authority: Pubkey,
    pub total_tokens: u64,
    pub graduation_threshold: u64,
    pub curve_slope: u64,
    pub is_paused: bool,
    pub total_graduated: u64,
    pub total_volume: u64,
}

#[account]
pub struct BondingCurve {
    pub mint: Pubkey,
    pub creator: Pubkey,
    pub total_supply: u64,
    pub circulating_supply: u64,
    pub sol_reserves: u64,
    pub is_graduated: bool,
    pub created_at: i64,
    pub graduated_at: Option<i64>,
    pub liquidity_pool: Option<Pubkey>,
    pub total_buys: u64,
    pub total_sells: u64,
}

// 错误码
#[error_code]
pub enum ErrorCode {
    #[msg("Token name too long")]
    NameTooLong,
    #[msg("Token symbol too long")]
    SymbolTooLong,
    #[msg("Invalid supply amount")]
    InvalidSupply,
    #[msg("Invalid amount")]
    InvalidAmount,
    #[msg("Token has graduated")]
    TokenGraduated,
    #[msg("Exceeds total supply")]
    ExceedsSupply,
    #[msg("Insufficient supply")]
    InsufficientSupply,
    #[msg("Insufficient reserves")]
    InsufficientReserves,
    #[msg("Token already graduated")]
    TokenAlreadyGraduated,
    #[msg("Threshold not met")]
    ThresholdNotMet,
    #[msg("Unauthorized")]
    Unauthorized,
    #[msg("Token not graduated")]
    TokenNotGraduated,
    #[msg("Liquidity pool already created")]
    PoolAlreadyCreated,
    #[msg("Operations are paused")]
    OperationsPaused,
}

// 事件定义
#[event]
pub struct TokenGraduatedEvent {
    pub mint: Pubkey,
    pub creator: Pubkey,
    pub final_market_cap: u64,
    pub total_supply: u64,
    pub timestamp: i64,
}

#[event]
pub struct TokenGraduationCompletedEvent {
    pub mint: Pubkey,
    pub creator: Pubkey,
    pub sol_for_liquidity: u64,
    pub sol_for_creator: u64,
    pub remaining_tokens: u64,
    pub dex_pool: Option<Pubkey>,
    pub timestamp: i64,
}

#[event]
pub struct TokenTradeEvent {
    pub mint: Pubkey,
    pub trader: Pubkey,
    pub is_buy: bool,
    pub token_amount: u64,
    pub sol_amount: u64,
    pub new_price: u64,
    pub market_cap: u64,
    pub timestamp: i64,
}

#[event]
pub struct EmergencyPauseEvent {
    pub authority: Pubkey,
    pub timestamp: i64,
}

#[event]
pub struct ResumeOperationsEvent {
    pub authority: Pubkey,
    pub timestamp: i64,
}
